use crate::action::device::DeleteStatus;
use crate::data::message::Message;
use crate::fairing::device::DeviceDb;
use crate::guard::userauth::AdminUserData;
use crate::model::device::{DeviceId, DeviceIdNum};
use rocket::http::Status;
use rocket::request::Request;
use rocket::response::{self, Responder, Response};
use rocket::route::Route;
use rocket::serde::json::Json;
use rocket_db_pools::{
    sqlx::{self, Acquire},
    Connection,
};

enum DeleteDeviceStatus {
    Deleted,
    NoDeviceDeleted,
    Failed(sqlx::Error),
}

impl<'r> Responder<'r, 'static> for DeleteDeviceStatus {
    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
        match self {
            DeleteDeviceStatus::Deleted => Response::build().status(Status::NoContent).ok(),
            DeleteDeviceStatus::NoDeviceDeleted => Response::build().status(Status::NotFound).ok(),
            DeleteDeviceStatus::Failed(err) => Response::build_from(
                Json(Message {
                    message: err.to_string(),
                })
                .respond_to(req)?,
            )
            .status(Status::InternalServerError)
            .ok(),
        }
    }
}

#[delete("/<id>")]
async fn delete(
    mut db: Connection<DeviceDb>,
    _device: AdminUserData,
    id: DeviceIdNum,
) -> DeleteDeviceStatus {
    let result = async {
        let mut tx = db.begin().await?;

        let id = DeviceId(id);
        let status = id.delete_device(&mut tx).await?;

        tx.commit().await?;
        Ok(match status {
            DeleteStatus::Deleted => DeleteDeviceStatus::Deleted,
            DeleteStatus::NotFound => DeleteDeviceStatus::NoDeviceDeleted,
        })
    }
    .await;
    match result {
        Ok(status) => status,
        Err(err) => DeleteDeviceStatus::Failed(err),
    }
}

pub fn route() -> Vec<Route> {
    routes![delete]
}
